package com.hooya.fa.eu.biz.dao.manager.special;

import com.hooya.fa.eu.api.enums.CkEnum;
import com.hooya.fa.eu.biz.dao.entity.TempKcjlDaily;
import com.hooya.fa.eu.biz.dao.entity.TempXsjl;
import com.hooya.fa.eu.biz.dao.entity.TempXsjlDelete;
import com.hooya.fa.eu.biz.dao.entity.TradeRecord;
import com.hooya.fa.eu.biz.dao.manager.GeneratorEntityManager;
import com.hooya.integrated.common.core.util.BeanCopyUtils;
import com.hooya.integrated.common.core.util.DoubleUtil;
import com.hooya.integrated.common.core.util.RedisUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.hooya.fa.eu.api.constant.DictConstant.*;

/**
 * @Description 1
 * @Author : Zongz
 * @Copyright Copyright (c) 豪雅集团
 * @Create 2024/3/11
 * @Version 1.0.0
 */
@Slf4j
@Component
@AllArgsConstructor
public class PkpyManager {

    private final GeneratorEntityManager entityManager;

    /**
     * 处理需要扣减的仓库记录
     *
     * @param deleteFdsXsjl        删除fds销售记录的计数
     * @param minusInventoryList   需要删除的仓库记录
     * @param minusMap             扣减map -> place： sku： belongs
     * @param metaWarehouseMap     进仓公司字典
     * @param inventoryList        仓库记录
     * @param inventoryBakList     仓库记录备份
     * @param tradeRecordList      交易记录集合
     * @param excludFbaSfaXsjlList 当日除sfa与fba的销售数据
     * @param tempXsjlDeleteList   销售删除集合
     */
    public void dealWithMinusInventoryList(AtomicInteger deleteFdsXsjl,
                                           List<TempKcjlDaily> minusInventoryList,
                                           Map<String, Map<String, Map<String, Integer>>> minusMap,
                                           Map<String, String> metaWarehouseMap,
                                           List<TempKcjlDaily> inventoryList,
                                           List<TempKcjlDaily> inventoryBakList,
                                           List<TradeRecord> tradeRecordList,
                                           List<TempXsjl> excludFbaSfaXsjlList,
                                           List<TempXsjlDelete> tempXsjlDeleteList) {
        List<String> restockMarkList =
                new ArrayList<>(RedisUtils.sGet(DICT_PREFIX + CkEnum.RESTOCK_MARK_LIST.getName()));
        minusMap.forEach((place, skuMap) -> {
            String origin = metaWarehouseMap.get(place);
            String costWayBelongs = "COSTWAY-" + origin;
            String fdsBelongs = "FDS-" + origin;
//            inventoryPkpy(costWayBelongs, fdsBelongs, place, )
            //原始仓库该place与belongs（fds/costway）的数据条数
            int costWaySkuSize = getSkuSize(inventoryBakList, place, costWayBelongs).size();
            int fdsSkuSize = getSkuSize(inventoryBakList, place, fdsBelongs).size();
            //需要被减扣place与belongs（fds/costway）条件的数据体条数
            AtomicInteger minusCostWayAllSkuSize =
                    new AtomicInteger(getSkuSize(minusInventoryList, place, costWayBelongs).size());
            AtomicInteger minusFdsAllSkuSize =
                    new AtomicInteger(getSkuSize(minusInventoryList, place, fdsBelongs).size());
            //所有盘亏盘盈产品个数/所有产品个数（fds/costway）
            double costWayRatio = costWaySkuSize == 0 ? 0D : DoubleUtil.div(minusCostWayAllSkuSize.get(), costWaySkuSize, 2);
            double fdsRatio = fdsSkuSize == 0 ? 0D : DoubleUtil.div(minusFdsAllSkuSize.get(), fdsSkuSize, 2);
            //单个sku的处理
            Map<String, Map<String, Integer>> sortedMap = new LinkedHashMap<>();
            skuMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(o -> sortedMap.put(o.getKey(), o.getValue()));
            sortedMap.forEach((sku, belongsMap) -> {
                List<TempKcjlDaily> costWayKcjl = inventoryBakList.stream().filter(
                        l -> l.getCpbh().equals(sku) && l.getPlace().equals(place) &&
                                l.getBelongs().equals(costWayBelongs)).collect(Collectors.toList());
                List<TempKcjlDaily> fdsKcjl = inventoryBakList.stream().filter(
                        l -> l.getCpbh().equals(sku) && l.getPlace().equals(place) &&
                                l.getBelongs().equals(fdsBelongs)).collect(Collectors.toList());
                AtomicInteger minusCostWayNum = new AtomicInteger(Optional.ofNullable(belongsMap.get(costWayBelongs)).orElse(0));
                AtomicInteger minusFdsNum = new AtomicInteger(Optional.ofNullable(belongsMap.get(fdsBelongs)).orElse(0));
                //fds
                if ((fdsKcjl.size() > 0 && minusFdsNum.get() <= 0)) {
                    //fds盘亏盘盈只能小于0的情况
                    if (costWayKcjl.size() > 0 && (costWayRatio <= 0.4 || minusCostWayNum.get() >= 0) && minusFdsNum.get() != 0) {
                        singleSkuPkpy(place, sku, costWayBelongs, fdsBelongs, minusInventoryList, inventoryList,
                                excludFbaSfaXsjlList, tradeRecordList, costWaySkuSize, minusCostWayAllSkuSize,
                                minusFdsAllSkuSize, minusCostWayNum, minusFdsNum, "costway", "fds");
                    }
                    if (minusFdsNum.get() <= 0) {
                        //fds盘亏盘盈 小于等于 0
                        onlyBelongsSumEnough(place, sku, fdsBelongs, inventoryList, restockMarkList,
                                excludFbaSfaXsjlList, deleteFdsXsjl, tempXsjlDeleteList, tradeRecordList,
                                minusFdsNum, minusFdsAllSkuSize, minusInventoryList);
                    }
                }
                //costway
                if ((costWayKcjl.size() > 0 && minusCostWayNum.get() <= 0)) {
                    if (fdsKcjl.size() > 0 && (fdsRatio <= 0.4 || minusFdsNum.get() >= 0) && minusCostWayNum.get() != 0) {
                        //与fds部分参数相反
                        singleSkuPkpy(place, sku, fdsBelongs, costWayBelongs, minusInventoryList, inventoryList,
                                excludFbaSfaXsjlList, tradeRecordList, fdsSkuSize, minusFdsAllSkuSize,
                                minusCostWayAllSkuSize, minusFdsNum, minusCostWayNum, "fds", "costway");
                    }
                    if (minusCostWayNum.get() <= 0) {
                        onlyBelongsSumEnough(place, sku, costWayBelongs, inventoryList, restockMarkList,
                                excludFbaSfaXsjlList, deleteFdsXsjl, tempXsjlDeleteList, tradeRecordList,
                                minusCostWayNum, minusCostWayAllSkuSize, minusInventoryList);
                    }
                }
            });
            if (fdsSkuSize != 0) {
                batchSkuPkpy(restockMarkList, minusFdsAllSkuSize, fdsSkuSize, fdsBelongs, place, deleteFdsXsjl,
                        minusInventoryList, skuMap, tempXsjlDeleteList, excludFbaSfaXsjlList, inventoryList, tradeRecordList);
            }
            if (costWaySkuSize != 0) {
                batchSkuPkpy(restockMarkList, minusCostWayAllSkuSize, costWaySkuSize, costWayBelongs, place, deleteFdsXsjl,
                        minusInventoryList, skuMap, tempXsjlDeleteList, excludFbaSfaXsjlList, inventoryList, tradeRecordList);
            }
        });
    }

    /**
     * 批量处理sku的盘亏盘盈
     *
     * @param minusAllSkuSize    需要被扣减的sku的数量（fds/costWay）
     * @param skuSize            仓库所有sku的数量（fds/costWay）
     * @param belongs            货权（fds/costWay）
     * @param place              出货地
     * @param deleteFdsXsjl      记录删除销售数据的数量
     * @param minusInventoryList 需要被删除的仓库记录
     * @param skuMap             sku对应map -> belongs：num
     * @param tempXsjlDeleteList 销售删除集合
     * @param tempXsjlList       销售记录集合
     * @param inventoryList      仓库记录
     * @param tradeRecordList    买卖记录
     */
    private void batchSkuPkpy(List<String> restockMarkList, AtomicInteger minusAllSkuSize,
                              int skuSize, String belongs, String place,
                              AtomicInteger deleteFdsXsjl, List<TempKcjlDaily> minusInventoryList,
                              Map<String, Map<String, Integer>> skuMap,
                              List<TempXsjlDelete> tempXsjlDeleteList, List<TempXsjl> tempXsjlList,
                              List<TempKcjlDaily> inventoryList, List<TradeRecord> tradeRecordList) {
        //所有sku处理
        double ratio = DoubleUtil.div(minusAllSkuSize.get(), skuSize, 2);
        if (ratio > 0.4d && skuSize > 0) {
            if (minusInventoryList.stream().anyMatch(l -> l.getPlace().equals(place) &&
                    l.getBelongs().equals(belongs) && l.getSl() < 0)) {
                try {
                    if (CollectionUtils.isEmpty(skuMap)) {
                        return;
                    }
                    skuMap.forEach((sku, belongsMap) -> {
                        int num = Optional.ofNullable(belongsMap.get(belongs)).orElse(0);
                        int xsAllNum = tempXsjlList.stream().filter(l -> l.getChck().equals(place) &&
                                l.getCpbh().equals(sku) && !companyMap.containsKey(l.getCompany()) &&
                                !restockMarkList.contains(l.getRestockMark())).mapToInt(TempXsjl::getSl).sum();
                        int xsRemaining = num + xsAllNum;
                        if (num < 0 && (xsRemaining >= 0 || deleteFdsXsjl.get() - xsRemaining <= 800)) {
                            List<TempXsjl> companyXsList = tempXsjlList.stream().filter(l -> l.getChck().equals(place) &&
                                            l.getCpbh().equals(sku) && l.getBelongs().equals(belongs) &&
                                            deleteCompanyList.containsKey(l.getCompany()))
                                    .sorted(Comparator.comparingInt(data -> deleteCompanyList.get(data.getCompany())))
                                    .sorted(Comparator.comparing(TempXsjl::getSl))
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(companyXsList)) {
                                List<TempXsjl> curRemoveXsjl = new LinkedList<>();
                                for (TempXsjl xsjl : companyXsList) {
                                    if (tempXsjlDeleteList.stream().anyMatch(
                                            l -> l.getSheetNumber().equals(xsjl.getSheetNumber()))) {
                                        continue;
                                    }
                                    TempXsjlDelete tempXsjlDelete =
                                            BeanCopyUtils.copyPropertiesNew(xsjl, TempXsjlDelete::new);
                                    tempXsjlDeleteList.add(tempXsjlDelete);
                                    curRemoveXsjl.add(xsjl);
                                    List<TempKcjlDaily> minusKcjl = minusInventoryList.stream().filter(
                                            l -> l.getPlace().equals(place) && l.getCpbh().equals(sku) &&
                                                    l.getBelongs().equals(belongs)).collect(Collectors.toList());
                                    if (!CollectionUtils.isEmpty(minusKcjl)) {
                                        minusKcjl.forEach(l -> l.setSl(l.getSl() + xsjl.getSl()));
                                        inventoryList.stream().filter(l -> l.getPlace().equals(place) &&
                                                        l.getCpbh().equals(sku) && l.getBelongs().equals(belongs))
                                                .forEach(l -> l.setSl(l.getSl() + xsjl.getSl()));
                                        deleteFdsXsjl.addAndGet(xsjl.getSl());
                                        //python的逻辑有点rz，这里做更改,对应sum>=0后，进行了下面这个操作
                                        //negativeKcjl = negativeKcjl.loc[negativeKcjl['sl'] != 0].copy()
                                        if (minusKcjl.stream().anyMatch(l -> l.getSl() >= 0)) {
                                            while (minusKcjl.iterator().hasNext()) {
                                                TempKcjlDaily kcjl = minusKcjl.iterator().next();
                                                if (kcjl.getSl() == 0) {
                                                    minusKcjl.iterator().remove();
                                                }
                                            }
                                        }
                                    }
                                }
                                tempXsjlList.removeAll(curRemoveXsjl);
                                List<TradeRecord> removeTrade = tradeRecordList.stream().filter(
                                                l -> curRemoveXsjl.stream().map(TempXsjl::getSheetNumber)
                                                        .collect(Collectors.toList()).contains(l.getSheetnumber()))
                                        .collect(Collectors.toList());
                                tradeRecordList.removeAll(removeTrade);
                            }
                        }
                        minusAllSkuSize.decrementAndGet();
                        if (DoubleUtil.div(minusAllSkuSize.get(), skuSize, 2) <= 0.4) {
                            throw new RuntimeException("StopIteration");
                        }
                    });
                } catch (RuntimeException e) {
                    if (!"StopIteration".equals(e.getMessage())) {
                        log.error(e.getMessage());
                        throw e; // 如果不是我们抛出的异常，则重新抛出
                    }
                }
            }
        }
    }

    /**
     * 处理单个sku的盘亏盘盈
     *
     * @param place                  出货地
     * @param sku                    产品编号
     * @param costWayBelongs         costWay货权
     * @param fdsBelongs             fds货权
     * @param minusInventoryList     需要扣减的仓库记录
     * @param inventoryList          仓库记录
     * @param excludFbaSfaXsjlList   当日除sfa与fba的销售数据
     * @param tradeRecordList        买卖记录集合
     * @param skuTotalSize           所有sku数量
     * @param minusCostWayAllSkuSize 需要被扣减的costWay的sku数量
     * @param minusFdsAllSkuSize     需要被扣减的fds的sku数量
     * @param minusCostWayNum        需要被扣减的costWay货权的数量
     * @param minusFdsNum            需要被扣减的fds货权的数量
     * @param costWay                costWay/fds
     * @param fds                    fds/costWay
     */
    private void singleSkuPkpy(String place, String sku, String costWayBelongs, String fdsBelongs,
                               List<TempKcjlDaily> minusInventoryList, List<TempKcjlDaily> inventoryList,
                               List<TempXsjl> excludFbaSfaXsjlList, List<TradeRecord> tradeRecordList, int skuTotalSize,
                               AtomicInteger minusCostWayAllSkuSize, AtomicInteger minusFdsAllSkuSize,
                               AtomicInteger minusCostWayNum, AtomicInteger minusFdsNum, String costWay, String fds) {
        List<TempXsjl> companyXsList = excludFbaSfaXsjlList.stream().filter(l -> l.getChck().equals(place) &&
                        l.getCpbh().equals(sku) && l.getBelongs().equals(fdsBelongs) &&
                        deleteCompanyList.containsKey(l.getCompany()))
                .sorted(Comparator.comparingInt(data -> deleteCompanyList.get(data.getCompany())))
                .sorted(Comparator.comparing(TempXsjl::getSl))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(companyXsList)) {
            outerLopper:
            for (TempXsjl xsjl : companyXsList) {
                for (int i = 0; i < xsjl.getSl(); i++) {
                    int tempCostWaySum = minusCostWayNum.get() - 1;
                    int tempMinusCostWaySum;
                    if (getSkuSize(minusInventoryList, place, costWayBelongs).contains(sku)) {
                        tempMinusCostWaySum = minusCostWayAllSkuSize.get();
                    } else {
                        tempMinusCostWaySum = minusCostWayAllSkuSize.get() + 1;
                    }
                    if (DoubleUtil.div(tempMinusCostWaySum, skuTotalSize, 2) > 0.4d &&
                            tempCostWaySum < 0) {
                        break outerLopper;
                    }
                    minusCostWayNum.decrementAndGet();
                    if (!getSkuSize(minusInventoryList, place, costWayBelongs).contains(sku)) {
                        minusCostWayAllSkuSize.addAndGet(1);
                    }
                    minusFdsNum.addAndGet(1);
                    if (minusFdsNum.get() >= 0) {
                        minusFdsAllSkuSize.decrementAndGet();
                    }
                    minusInventoryList.stream().filter(l -> l.getPlace().equals(place) &&
                                    l.getCpbh().equals(sku) && l.getBelongs().equals(fdsBelongs))
                            .forEach(l -> l.setSl(l.getSl() + 1));
                    if (getSkuSize(minusInventoryList, place, costWayBelongs).contains(sku)) {
                        minusInventoryList.stream().filter(l -> l.getPlace().equals(place) &&
                                        l.getCpbh().equals(sku) && l.getBelongs().equals(costWayBelongs))
                                .forEach(l -> l.setSl(l.getSl() - 1));
                    } else {
                        minusInventoryList.add(
                                entityManager.genTempKcjlDaily(sku, costWayBelongs, place, -1, xsjl.getOrderDate()));
                    }
                    inventoryList.stream().filter(l -> l.getPlace().equals(place) &&
                                    l.getCpbh().equals(sku) && l.getBelongs().equals(fdsBelongs))
                            .forEach(l -> l.setSl(l.getSl() + 1));
                    if (inventoryList.stream().anyMatch(l -> l.getPlace().equals(place) &&
                            l.getCpbh().equals(sku) && l.getBelongs().equals(costWayBelongs))) {
                        inventoryList.stream().filter(l -> l.getPlace().equals(place) &&
                                        l.getCpbh().equals(sku) && l.getBelongs().equals(costWayBelongs))
                                .forEach(l -> l.setSl(l.getSl() - 1));
                    } else {
                        inventoryList.add(
                                entityManager.genTempKcjlDaily(sku, costWayBelongs, place, -1, xsjl.getOrderDate()));
                    }
                    if (!costWay.equals(xsjl.getCompany())) {
                        if (tradeRecordList.stream().anyMatch(
                                l -> l.getSheetnumber().equals(xsjl.getSheetNumber()) &&
                                        l.getFromcompany().equals(costWayBelongs.toLowerCase()))) {
                            tradeRecordList.stream().filter(
                                            l -> l.getSheetnumber().equals(xsjl.getSheetNumber()) &&
                                                    l.getFromcompany().equals(costWayBelongs.toLowerCase()))
                                    .forEach(l -> l.setMmsl(l.getMmsl() + 1));
                        } else {
                            tradeRecordList.add(entityManager.genTradeRecord(xsjl, 1,
                                    costWayBelongs.toLowerCase(), xsjl.getCompany(), xsjl.getFromCountry(),
                                    xsjl.getToCountry(), ""));
                        }
                    }
                    if (!fds.equals(xsjl.getCompany())) {
                        int sum = tradeRecordList.stream().filter(
                                        l -> l.getSheetnumber().equals(xsjl.getSheetNumber()) &&
                                                l.getFromcompany().equals(fdsBelongs.toLowerCase()))
                                .mapToInt(TradeRecord::getMmsl).sum();
                        if (sum > 0) {
                            tradeRecordList.stream().filter(
                                            l -> l.getSheetnumber().equals(xsjl.getSheetNumber()) &&
                                                    l.getFromcompany().equals(fdsBelongs.toLowerCase()))
                                    .forEach(l -> l.setMmsl(l.getMmsl() - 1));
                            if (sum - 1 == 0) {
                                List<TradeRecord> removeTradeList = tradeRecordList.stream().filter(l -> l.getMmsl() == 0).collect(Collectors.toList());
                                tradeRecordList.removeAll(removeTradeList);
                                break outerLopper;
                            }
                        }
                    }
                    Iterator<TempKcjlDaily> iterator = minusInventoryList.iterator();
                    while (iterator.hasNext()) {
                        TempKcjlDaily kc = iterator.next();
                        if (kc.getSl() == 0) {
                            iterator.remove();
                        }
                    }
                    if (minusFdsNum.get() >= 0) {
                        break outerLopper;
                    }
                }
            }
        }
    }

    /**
     * 处理货权数量小于0的情况
     *
     * @param place                出货地
     * @param sku                  产品编号
     * @param belongs              货权
     * @param inventoryList        仓库列表
     * @param excludFbaSfaXsjlList 当日除sfa与fba的销售数据
     * @param deleteFdsXsjl        销售记录删除数
     * @param tempXsjlDeleteList   销售删除集合
     * @param tradeRecordList      买卖记录集合
     * @param minusNum             扣减数量
     * @param minusAllSkuSize      被扣减的所有sku（不重复）数量数量
     * @param minusInventoryList   需要被扣减的仓库记录
     */
    private void onlyBelongsSumEnough(String place, String sku, String belongs, List<TempKcjlDaily> inventoryList,
                                      List<String> restockMarkList, List<TempXsjl> excludFbaSfaXsjlList,
                                      AtomicInteger deleteFdsXsjl, List<TempXsjlDelete> tempXsjlDeleteList,
                                      List<TradeRecord> tradeRecordList, AtomicInteger minusNum,
                                      AtomicInteger minusAllSkuSize, List<TempKcjlDaily> minusInventoryList) {
        List<TempXsjl> companyXsList = excludFbaSfaXsjlList.stream().filter(l -> l.getChck().equals(place) &&
                        l.getCpbh().equals(sku) && l.getBelongs().equals(belongs) &&
                        deleteCompanyList.containsKey(l.getCompany()) &&
                        !restockMarkList.contains(l.getRestockMark()))
                .sorted(Comparator.comparingInt(data -> deleteCompanyList.get(data.getCompany())))
                .sorted(Comparator.comparing(TempXsjl::getSl))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(companyXsList)) {
            for (TempXsjl xsjl : companyXsList) {
                String sheetNumber = xsjl.getSheetNumber();
                if ((xsjl.getCompany().equals("fds") && deleteFdsXsjl.get() + xsjl.getSl() >= 800) ||
                        xsjl.getCompany().equals("costway") ||
                        (!CollectionUtils.isEmpty(tempXsjlDeleteList) &&
                                tempXsjlDeleteList.stream().map(TempXsjlDelete::getSheetNumber)
                                        .collect(Collectors.toSet()).contains(sheetNumber))) {
                    continue;
                }
                TempXsjlDelete tempXsjlDelete = BeanCopyUtils.copyPropertiesNew(xsjl, TempXsjlDelete::new);
                tempXsjlDeleteList.add(tempXsjlDelete);
                minusNum.addAndGet(xsjl.getSl());
                if (minusNum.get() >= 0) {
                    minusAllSkuSize.decrementAndGet();
                }
                minusInventoryList.stream().filter(l ->
                                l.getPlace().equals(place) && l.getCpbh().equals(sku) &&
                                        l.getBelongs().equals(belongs))
                        .forEach(l -> l.setSl(l.getSl() + xsjl.getSl()));
                inventoryList.stream().filter(l ->
                                l.getPlace().equals(place) && l.getCpbh().equals(sku) &&
                                        l.getBelongs().equals(belongs))
                        .forEach(l -> l.setSl(l.getSl() + xsjl.getSl()));
                List<TradeRecord> removeTrade = tradeRecordList.stream()
                        .filter(l -> StringUtils.isNotBlank(l.getSheetnumber()) &&
                                l.getSheetnumber().equals(sheetNumber)).collect(Collectors.toList());
                tradeRecordList.removeAll(removeTrade);
                List<TempKcjlDaily> removeMinusKc = minusInventoryList.stream().filter(l -> l.getSl() == 0)
                        .collect(Collectors.toList());
                minusInventoryList.removeAll(removeMinusKc);
                if (xsjl.getCompany().equals("fds")) {
                    deleteFdsXsjl.addAndGet(xsjl.getSl());
                    if (deleteFdsXsjl.get() >= 800) {
                        break;
                    }
                }
                if (minusNum.get() > 0) {
                    break;
                }
            }
        }
    }

    /**
     * 获取仓库记录所有产品编号的集合
     *
     * @param kcjl
     * @param place
     * @param belongs
     * @return
     */
    private Set<String> getSkuSize(List<TempKcjlDaily> kcjl, String place, String belongs) {
        return kcjl.stream().filter(l -> l.getPlace().equals(place) &&
                        l.getBelongs().equals(belongs)).map(TempKcjlDaily::getCpbh)
                .collect(Collectors.toSet());
    }


}
